package com.techsoul.module.system.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.techsoul.common.core.constant.ApiConstants;
import com.techsoul.common.core.exception.ParamException;
import com.techsoul.common.core.exception.file.FileUploadException;
import com.techsoul.common.core.util.ServletUtils;
import com.techsoul.common.core.util.bean.BeanUtils;
import com.techsoul.common.core.util.collection.ListUtils;
import com.techsoul.common.core.util.file.FileUtils;
import com.techsoul.common.core.util.id.IdWorker;
import com.techsoul.common.core.util.lang.StringUtils;
import com.techsoul.common.security.pojo.LoginUser;
import com.techsoul.common.security.service.TokenService;
import com.techsoul.module.system.mapper.AttachmentMapper;
import com.techsoul.module.system.pojo.entity.Attachment;
import com.techsoul.module.system.pojo.param.AttachmentSaveParam;
import com.techsoul.module.system.pojo.param.AttachmentSearchParam;
import com.techsoul.module.system.pojo.vo.AttachmentVo;
import com.techsoul.module.system.service.IAttachmentService;
import com.techsoul.module.system.service.IConfigService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.List;

/**
 * 附件 Service实现
 *
 * @author liuen
 * @date 2021-06-03
 */
@Slf4j
@Service
@Transactional(readOnly = true)
public class AttachmentServiceImpl implements IAttachmentService {

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private AttachmentMapper mapper;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private IConfigService configService;

    @Value("${project.attachment.extensions}")
    private String extensions;

    /**
     * 新增
     * @param params
     * @return
     */
    @Transactional(readOnly = false)
    @Override
    public String insert(AttachmentSaveParam params) {
        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
        Attachment entity = new Attachment();
        BeanUtils.copyProperties(params, entity);
        entity.setId(idWorker.nextId() + "")
                .preInsert(loginUser == null ? "1" : loginUser.getUser().getId());
        this.mapper.insert(entity);
        params.setId(entity.getId());
        return entity.getId();
    }

    /**
     * 删除
     * @param id
     * @return
     */
    @Transactional(readOnly = false)
    @Override
    public Integer delete(String id) {
        return this.mapper.deleteById(id);
    }

    /**
     * 批量删除
     * @param idList
     */
    @Transactional(readOnly = false)
    @Override
    public Integer batchDelete(List<String> idList) {
        if (ListUtils.isNotEmpty(idList)) {
            return this.mapper.deleteBatchIds(idList);
        } else {
            return 0;
        }
    }

    /**
     * 修改
     * @param params
     * @return
     */
    @Transactional(readOnly = false)
    @Override
    public Integer update(AttachmentSaveParam params) {
        Attachment entityFromDb = this.mapper.selectById(params.getId());
        if (entityFromDb == null) {
            throw new ParamException("id=" + params.getId());
        }
        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
        BeanUtils.copyProperties(params, entityFromDb);
        entityFromDb.preUpdate(loginUser == null ? ApiConstants.DEFAULT_USER_ID : loginUser.getUser().getId());
        return this.mapper.updateById(entityFromDb);
    }

    /**
     * 详情
     * @param id
     * @return
     */
    @Override
    public AttachmentVo findById(String id) {
        return this.mapper.findById(id);
    }

    /**
     * 列表
     * @param params
     * @return
     */
    @Override
    public List<AttachmentVo> findAll(AttachmentSearchParam params) {
        return this.mapper.findAll(params);
    }

    /**
     * 列表-分页
     * @param params
     * @param current
     * @param pageSize
     * @return
     */
    @Override
    public IPage<AttachmentVo> findAll(AttachmentSearchParam params, Integer current, Integer pageSize) {
        return this.mapper.findAll(new Page<>(current, pageSize), params);
    }

    /**
     * 上传附件
     * @param request
     * @return
     */
    @Transactional(readOnly = false)
    @Override
    public List<Attachment> upload(MultipartHttpServletRequest request) {
        List<Attachment> attachments = ListUtils.newArrayList();
        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
        String baseDir = configService.findByConfigKey("project.attachment.baseDir");
        try {
            // 判断文件是否存在
            if (request.getMultiFileMap() != null) {
                Iterator<String> fileNames = request.getFileNames(); // 取得request中的所有文件名
                int seq = 1;
                while (fileNames.hasNext()) {
                    // 源文件
                    MultipartFile originalFile = request.getFile(fileNames.next());
                    if (originalFile != null) {
                        // 源文件名称
                        String originalFilename = originalFile.getOriginalFilename();
                        if (StringUtils.isNotBlank(originalFilename)) {
                            // 源文件扩展名
                            String fileExtension = FileUtils.getFileExtension(originalFilename);
                            if (extensions.contains(fileExtension)) {
                                // 目标文件名
                                String descFilename = idWorker.nextId() + "." + fileExtension;
                                File descFile = new File(baseDir + "/" + descFilename);
                                // 如果目标文件所在的目录不存在，则创建目录
                                if (!descFile.getParentFile().exists()) {
                                    descFile.getParentFile().mkdirs();
                                }
                                // 保存文件到指定路径
                                originalFile.transferTo(descFile);
                                // 插入附件表记录，异步调用时，不能获取用户信息，对loginUser为null做兼容
                                Attachment attachment = new Attachment();
                                attachment.setTableCode(request.getParameter("tableCode"))
                                        .setTableKey(request.getParameter("tableKey"))
                                        .setFileName(originalFilename)
                                        .setFileUrl(descFilename)
                                        .setExtension(fileExtension)
                                        .setSeq(seq++)
                                        .setId(idWorker.nextId() + "")
                                        .preInsert(loginUser == null ? ApiConstants.DEFAULT_USER_ID : loginUser.getUser().getId());
                                this.mapper.insert(attachment);
                                attachments.add(attachment);
                            } else {
                                throw new FileUploadException(originalFilename + "-不支持该类型文件上传");
                            }
                        }
                    }
                }
            }
        } catch (IOException e) {
            log.error("文件上传失败", e);
            throw new FileUploadException(e);
        }
        return attachments;
    }

}
